package com.lindroy.androidplayer.extensions

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.lindroy.androidplayer.R
import com.lindroy.androidplayer.base.BaseActivity
import com.lindroy.androidplayer.base.BaseFragment
import com.lindroy.androidplayer.base.viewmodel.BaseViewModel
import com.lindroy.androidplayer.logic.model.HttpResult
import com.lindroy.androidplayer.logic.network2.*
import com.lindroy.androidplayer.logic.network2.state.*
import com.lindroy.androidplayer.logic.network2.state.Error
import com.lindroy.lib_utils.extensions.getResString
import com.orhanobut.logger.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch

/**
 * @author Lin
 * @date 2021/4/15
 * @function BaseViewModel的扩展方法
 */
fun <T> BaseViewModel.request(
    block: suspend () -> HttpResult<T>,
    resultState: MutableLiveData<ResultState<T>>,
    isShowDialog: Boolean = false,
    loadingMsg: String = getResString(R.string.loading)
): Job = viewModelScope.launch {
    kotlin.runCatching {//runCatching处理错误结果
        resultState.value = ResultState.onLoading(loadingMsg)
        isShowDialog.yes {
            loadingChange.showDialog.postValue(loadingMsg)
        }
        block()
    }.onSuccess {
        isShowDialog.yes {
            loadingChange.dismissDialog.postValue(false)
        }
        resultState.requestResult(it)
    }.onFailure {
        isShowDialog.yes {
            loadingChange.dismissDialog.postValue(false)
        }
        resultState.paresException(it)
        Logger.e(it.message ?: "Unknown Failure")
    }
}

fun <T> BaseFragment.parseState(
    resultState: ResultState<T>,
    onLoading: (() -> Unit)? = null,
    onError: ((AppException) -> Unit)? = null,
    onSuccess: (T) -> Unit
) {
    when (resultState) {
        is Loading -> {
//            showLoading(resultState.loadingMsg)
            onLoading?.invoke()
        }
        is Error -> {
//            dismissLoading()
            onError?.invoke(resultState.error)
        }
        is Success -> {
//            dismissLoading()
            onSuccess(resultState.data)
        }
    }
}

fun <T> BaseActivity.parseState(
    resultState: ResultState<T>,
    onLoading: (() -> Unit)? = null,
    onError: ((AppException) -> Unit)? = null,
    onSuccess: (T) -> Unit
) {
    when (resultState) {
        is Loading -> {
//            showLoading(resultState.loadingMsg)
            onLoading?.invoke()
        }
        is Error -> {
//            dismissLoading()
            onError?.invoke(resultState.error)
        }
        is Success -> {
//            dismissLoading()
            onSuccess(resultState.data)
        }
    }
}

/**
 * 过滤服务器结果，失败抛异常
 * @param block 请求体方法，必须要用suspend关键字修饰
 * @param success 成功回调
 * @param error 失败回调 可不传
 * @param isShowDialog 是否显示加载框
 * @param loadingMessage 加载框提示内容
 * Todo(要想启动加载对话框，必须在)
 */
fun <T> BaseViewModel.request(
    block: suspend () -> HttpResult<T>,
    success: (T) -> Unit,
    error: (AppException) -> Unit = {},
    isShowDialog: Boolean = false,
    loadingMessage: String = "请求网络中..."
): Job {
    //如果需要弹窗 通知Activity/fragment弹窗
    return viewModelScope.launch {
        runCatching {
            if (isShowDialog) loadingChange.showDialog.postValue(loadingMessage)
            //请求体
            block()
        }.onSuccess {
            //网络请求成功 关闭弹窗
            if (isShowDialog) loadingChange.dismissDialog.postValue(false)
            runCatching {
                //校验请求结果码是否正确，不正确会抛出异常走下面的onFailure
                executeResponse(it) { t ->
                    success(t)
                }
            }.onFailure { e ->
                //打印错误消息
                e.message?.let { Logger.e(it) }
                //失败回调
                error(ExceptionHandle.handleException(e))
            }
        }.onFailure {
            //网络请求异常 关闭弹窗
            if (isShowDialog) loadingChange.dismissDialog.postValue(false)
            //打印错误消息
            it.message?.let { e -> Logger.e(e) }
            //失败回调
            error(ExceptionHandle.handleException(it))
        }
    }
}

/**
 * 请求结果过滤，判断请求服务器请求结果是否成功，不成功则会抛出异常
 */
suspend fun <T> executeResponse(
    response: HttpResult<T>,
    success: suspend CoroutineScope.(T) -> Unit
) {
    coroutineScope {
        when {
            response.success -> {
                success(response.data)
            }
            else -> {
                throw AppException(
                    response.errorCode,
                    response.errorMsg,
                    response.errorMsg
                )
            }
        }
    }
}